home *** CD-ROM | disk | FTP | other *** search
- unit WideInfo;
-
- interface
-
- uses TypInfo;
-
- // GetWideStrProp gets a WideString property value.
- // SetWideStrProp sets a WideString property value.
- function GetWideStrProp(Instance: TObject; PropInfo: PPropInfo): WideString;
- procedure SetWideStrProp(Instance: TObject; PropInfo: PPropInfo; const Value: WideString);
-
- // GetWideStrProp and SetWideStrProp require low-level access to
- // PropInfo. GetPropGetter and GetPropSetter provide that access by
- // obtaining the pointer where the property value is stored. These
- // procedure work for any type of property.
- //
- // When PtrType is ptData, Ptr is a pointer to the property value as
- // stored in a field of Instance. Cast Ptr to the correct type to fetch
- // or modify the value.
- //
- // When PtrType is ptCode, Ptr is a code pointer to a method that
- // gets or sets the value. Instance is the data part of the method.
- // Call the method to get or set the value. Note that if PropInfo.Index
- // is not equal to Low(Integer) (that is, $80000000), the property is
- // an indexed property, so you must pass the index value as the first
- // argument (after Self). Cast Ptr to the appropriate function type.
- // The getter return type must match the property type. The setter
- // procedure's last parameter type must match the property type.
- type
- TPtrType = (ptCode, ptData);
- procedure GetPropGetter(Instance: TObject; PropInfo: PPropInfo; var PtrType: TPtrType; var Ptr: Pointer);
- procedure GetPropSetter(Instance: TObject; PropInfo: PPropInfo; var PtrType: TPtrType; var Ptr: Pointer);
-
- implementation
-
- uses Consts, SysUtils;
-
- resourcestring
- sWriteOnlyProperty = 'Property is write-only';
-
- const
- NoIndex = Low(Integer);
- type
- TWideStrProc = procedure(Instance: TObject; const Value: WideString) register;
- TWideStrIndexProc = procedure(Instance: TObject; Index: Integer; const Value: WideString) register;
- TWideStrFunc = function(Instance: TObject): WideString register;
- TWideStrIndexFunc = function(Instance: TObject; Index: Integer): WideString register;
- PPChar = ^PChar;
- PPointer = ^Pointer;
-
- // To help access the property value, GetPropValue gets a pointer
- // to the field or method. The PtrType parameter says what kind of
- // pointer it is. An exception is raised for any error.
- procedure GetPropGetter(Instance: TObject; PropInfo: PPropInfo; var PtrType: TPtrType; var Ptr: Pointer);
- var
- Mask: LongWord;
- begin
- // The high byte of GetProc determines how to interpret it.
- Mask := LongWord(PropInfo.GetProc) and $FF000000;
- if Mask = $FF000000 then
- begin
- // GetProc is a field offset in Instance. The low-order 3 bytes
- // specify the byte offset from the start of Instance. Treat
- // Instance as a pointer to add the offset, then dereference
- // that pointer to perform the simple WideString assignment.
- PtrType := ptData;
- Ptr := PChar(Instance) + LongInt(PropInfo.GetProc) and $FFFFFF;
- end
- else
- begin
- // Otherwise, GetProc is a reference to a method, either virtual or static.
- PtrType := ptCode;
- if Mask = $FE000000 then
- begin
- // GetProc is a virtual function offset. Only the low-order 2 bytes
- // are used for the offset into the VMT.
- // The first field in Instance is a pointer to a VMT, which is a list
- // of pointers to functions. Use the offset into the VMT to get the
- // actual method pointer.
- Ptr := PPChar(Instance)^ + LongRec(PropInfo.GetProc).Lo;
- Ptr := PPointer(Ptr)^;
- end
- else
- begin
- // GetProc is a static method pointer.
- Ptr := PropInfo.GetProc;
- if Ptr = nil then
- // No GetProc at all!
- raise EPropWriteOnly.Create(sWriteOnlyProperty);
- end;
- end;
- end;
-
- procedure GetPropSetter(Instance: TObject; PropInfo: PPropInfo; var PtrType: TPtrType; var Ptr: Pointer);
- var
- Mask: LongWord;
- begin
- // The high byte of SetProc determines how to interpret it.
- Mask := LongWord(PropInfo.SetProc) and $FF000000;
- if Mask = $FF000000 then
- begin
- // SetProc is a field offset in Instance. The low-order 3 bytes
- // specify the byte offset from the start of Instance. Treat
- // Instance as a pointer to add the offset, then dereference
- // that pointer to perform the simple WideString assignment.
- PtrType := ptData;
- Ptr := PChar(Instance) + LongInt(PropInfo.SetProc) and $FFFFFF;
- end
- else
- begin
- // Otherwise, SetProc is a reference to a method, either virtual or static.
- PtrType := ptCode;
- if Mask = $FE000000 then
- begin
- // SetProc is a virtual function offset. Only the low-order 2 bytes
- // are used for the offset into the VMT.
- // The first field in Instance is a pointer to a VMT, which is a list
- // of pointers to functions. Use the offset into the VMT to get the
- // actual method pointer.
- Ptr := PPChar(Instance)^ + LongRec(PropInfo.SetProc).Lo;
- Ptr := PPointer(Ptr)^;
- end
- else
- begin
- // SetProc is a static method pointer.
- Ptr := PropInfo.SetProc;
- if Ptr = nil then
- // No SetProc at all!
- raise EPropReadOnly.Create(sReadOnlyProperty);
- end;
- end;
- end;
-
- // Delphi always converts a wide string to an ANSI string when setting
- // a property value. Call GetWideStrProp and SetWideStrProp to access
- // the property value as a real WideString.
- function GetWideStrProp(Instance: TObject; PropInfo: PPropInfo): WideString;
- var
- PtrType: TPtrType;
- Ptr: Pointer;
- begin
- GetPropGetter(Instance, PropInfo, PtrType, Ptr);
- if PtrType = ptData then
- Result := PWideString(Ptr)^
- else if PropInfo.Index <> NoIndex then
- // Indexed property, so call the GetProc with the index value.
- Result := TWideStrIndexFunc(Ptr)(Instance, PropInfo.Index)
- else
- // Not an indexed property, so just call the GetProc.
- Result := TWideStrFunc(Ptr)(Instance);
- end;
-
- procedure SetWideStrProp(Instance: TObject; PropInfo: PPropInfo; const Value: WideString);
- var
- PtrType: TPtrType;
- Ptr: Pointer;
- begin
- GetPropSetter(Instance, PropInfo, PtrType, Ptr);
- if PtrType = ptData then
- PWideString(Ptr)^ := Value
- else if PropInfo.Index <> NoIndex then
- // Indexed property, so call the SetProc with the index value.
- TWideStrIndexProc(Ptr)(Instance, PropInfo.Index, Value)
- else
- // Not an indexed property, so just call the SetProc.
- TWideStrProc(Ptr)(Instance, Value);
- end;
-
- end.
-